using System;
using System.Collections.Generic;
using System.Text;
using NBusiness.CodeDom;
using NBusiness.CodeDom.Compiler;
using NBusiness.ESharp.Compiler;

namespace NBusiness.ESharp
{
    [Serializable]
    internal class ESharpFamily : EntityFamily
    {        
        #region Attach
        protected internal override void Attach()
        {
            foreach (Entity e in Entities)
                e.Attach();

            foreach (EntityFamily family in Families.Values)
                family.Attach();
        } 
        #endregion

        #region Initialize Assignments
        protected override void InitializeAssignmentLogic()
        {
            //Family name
            Assignments.Add(new AssignmentLogic(
                ESharpParser.Expressions.Identifier,
                EntityElementType.FamilyName,
                new AssignmentLogicHandler(AssignFamilyName),
                EntityElementType.FamilyDeclaration));

            Assignments.Add(new AssignmentLogic(
                ESharpParser.Expressions.FamilyJoin,
                EntityElementType.FamilyJoin,
                EntityElementType.FamilyName));

            Assignments.Add(new AssignmentLogic(
                ESharpParser.Expressions.Identifier,
                EntityElementType.FamilyName,
                new AssignmentLogicHandler(BuildInnerFamily),
                EntityElementType.FamilyJoin));

            //Begin family
            Assignments.Add(new AssignmentLogic(
                ESharpParser.Expressions.GroupBegin,
                EntityElementType.FamilyBegin,
                EntityElementType.FamilyName));

            //Create an "entity"
            Assignments.Add(new AssignmentLogic(
                ESharpParser.Expressions.EntityDeclaration,
                EntityElementType.EntityDeclaration,
                new AssignmentLogicHandler(CreateNewEntity),
                EntityElementType.FamilyBegin,
                EntityElementType.StatementEnd,
                EntityElementType.EntityEnd));

            Assignments.Add(new AssignmentLogic(
                ESharpParser.Expressions.GroupEnd,
                EntityElementType.FamilyEnd,
                PostAssignmentAction.Stop,
                EntityElementType.Any));
        } 
        #endregion

        #region Assignments
        private void AssignFamilyName(object sender, AssignmentLogicEventArgs e)
        {
            Name = e.Elements.Peek().Value;
        }

        private void BuildInnerFamily(object sender, AssignmentLogicEventArgs e)
        {
            EntityElement element = e.Elements.Peek();
            if (Families.ContainsKey(element.Value))
            {
                Families[element.Value].Build(e.Elements, EntityElementType.FamilyName);
            }
            else
            {
                EntityFamily f = new ESharpFamily();
                f.BuildError += new EventHandler<EntityBuildErrorEventArgs>(child_ParseError);
                f.Name = element.Value;
                f.Parent = this;
                Families.Add(f.Name, f);
                f.Build(e.Elements, EntityElementType.FamilyName);

            }
        } 

        void child_ParseError(object sender, EntityBuildErrorEventArgs e)
        {
            OnBuildError(e.Error);
        }

        private void CreateNewEntity(object sender, AssignmentLogicEventArgs e)
        {
            ESharpEntity entity = new ESharpEntity();
            entity.BuildError += new EventHandler<EntityBuildErrorEventArgs>(child_ParseError);
            entity.Parent = this;
            entity.Build(e.Elements, EntityElementType.EntityDeclaration);

            bool match = false;
            foreach (Entity en in this.Entities)
            {
                if (entity.Name == en.Name)
                {
                    match = true;
                    break;
                }
            }

            if (!match)
                Entities.Add(entity);
            else
                OnBuildError(new ESharpBuildError(ESharpErrorCode.ES1001, entity.Elements[0]));
        }

        #endregion

        #region Get Element from child
        protected override EntityElement GetElementFromChild(string path, int line, int col)
        {
            EntityElement e = null;
            foreach (Entity entity in Entities)
            {
                e = entity.GetElementByLocation(path, line, col);
                if (e != null) break;
            }

            if (e == null)
            {
                foreach (EntityFamily family in Families.Values)
                {
                    e = family.GetElementByLocation(path, line, col);
                    if (e != null) break;
                }
            }

            return e;
        } 
        #endregion

        #region Get unit from child
        protected override EntityCompileUnit GetUnitFromChild(EntityElement element)
        {
            EntityCompileUnit unit = null;
            foreach (Entity entity in Entities)
            {
                unit = entity.GetUnitByElement(element);
                if (unit != null) break;
            }

            if (unit == null)
            {
                foreach (EntityFamily family in Families.Values)
                {
                    unit = family.GetUnitByElement(element);
                    if (unit != null) break;
                }
            }

            return unit;
        } 
        #endregion
    }
}
